home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 3 / Amiga Tools 3.iso / programming / jpegv6 / jpeg-6 / jpegtran.c < prev    next >
C/C++ Source or Header  |  1995-06-16  |  11KB  |  371 lines

  1. /*
  2.  * jpegtran.c
  3.  *
  4.  * Copyright (C) 1995, Thomas G. Lane.
  5.  * This file is part of the Independent JPEG Group's software.
  6.  * For conditions of distribution and use, see the accompanying README file.
  7.  *
  8.  * This file contains a command-line user interface for JPEG transcoding.
  9.  * It is very similar to cjpeg.c, but provides lossless transcoding between
  10.  * different JPEG file formats.
  11.  */
  12.  
  13. #include "cdjpeg.h"        /* Common decls for cjpeg/djpeg applications */
  14. #include "jversion.h"        /* for version message */
  15.  
  16. #ifdef USE_CCOMMAND        /* command-line reader for Macintosh */
  17. #ifdef __MWERKS__
  18. #include <SIOUX.h>              /* Metrowerks declares it here */
  19. #endif
  20. #ifdef THINK_C
  21. #include <console.h>        /* Think declares it here */
  22. #endif
  23. #endif
  24.  
  25.  
  26. /*
  27.  * Argument-parsing code.
  28.  * The switch parser is designed to be useful with DOS-style command line
  29.  * syntax, ie, intermixed switches and file names, where only the switches
  30.  * to the left of a given file name affect processing of that file.
  31.  * The main program in this file doesn't actually use this capability...
  32.  */
  33.  
  34.  
  35. static const char * progname;    /* program name for error messages */
  36. static char * outfilename;    /* for -outfile switch */
  37.  
  38.  
  39. LOCAL void
  40. usage (void)
  41. /* complain about bad command line */
  42. {
  43.   fprintf(stderr, "usage: %s [switches] ", progname);
  44. #ifdef TWO_FILE_COMMANDLINE
  45.   fprintf(stderr, "inputfile outputfile\n");
  46. #else
  47.   fprintf(stderr, "[inputfile]\n");
  48. #endif
  49.  
  50.   fprintf(stderr, "Switches (names may be abbreviated):\n");
  51. #ifdef ENTROPY_OPT_SUPPORTED
  52.   fprintf(stderr, "  -optimize      Optimize Huffman table (smaller file, but slow compression)\n");
  53. #endif
  54. #ifdef C_PROGRESSIVE_SUPPORTED
  55.   fprintf(stderr, "  -progressive   Create progressive JPEG file\n");
  56. #endif
  57.   fprintf(stderr, "Switches for advanced users:\n");
  58.   fprintf(stderr, "  -restart N     Set restart interval in rows, or in blocks with B\n");
  59.   fprintf(stderr, "  -maxmemory N   Maximum memory to use (in kbytes)\n");
  60.   fprintf(stderr, "  -outfile name  Specify name for output file\n");
  61.   fprintf(stderr, "  -verbose  or  -debug   Emit debug output\n");
  62.   fprintf(stderr, "Switches for wizards:\n");
  63. #ifdef C_ARITH_CODING_SUPPORTED
  64.   fprintf(stderr, "  -arithmetic    Use arithmetic coding\n");
  65. #endif
  66. #ifdef C_MULTISCAN_FILES_SUPPORTED
  67.   fprintf(stderr, "  -scans file    Create multi-scan JPEG per script file\n");
  68. #endif
  69.   exit(EXIT_FAILURE);
  70. }
  71.  
  72.  
  73. LOCAL int
  74. parse_switches (j_compress_ptr cinfo, int argc, char **argv,
  75.         int last_file_arg_seen, boolean for_real)
  76. /* Parse optional switches.
  77.  * Returns argv[] index of first file-name argument (== argc if none).
  78.  * Any file names with indexes <= last_file_arg_seen are ignored;
  79.  * they have presumably been processed in a previous iteration.
  80.  * (Pass 0 for last_file_arg_seen on the first or only iteration.)
  81.  * for_real is FALSE on the first (dummy) pass; we may skip any expensive
  82.  * processing.
  83.  */
  84. {
  85.   int argn;
  86.   char * arg;
  87.   boolean simple_progressive;
  88.   char * scansarg = NULL;    /* saves -scans parm if any */
  89.  
  90.   /* Set up default JPEG parameters. */
  91.   simple_progressive = FALSE;
  92.   outfilename = NULL;
  93.   cinfo->err->trace_level = 0;
  94.  
  95.   /* Scan command line options, adjust parameters */
  96.  
  97.   for (argn = 1; argn < argc; argn++) {
  98.     arg = argv[argn];
  99.     if (*arg != '-') {
  100.       /* Not a switch, must be a file name argument */
  101.       if (argn <= last_file_arg_seen) {
  102.     outfilename = NULL;    /* -outfile applies to just one input file */
  103.     continue;        /* ignore this name if previously processed */
  104.       }
  105.       break;            /* else done parsing switches */
  106.     }
  107.     arg++;            /* advance past switch marker character */
  108.  
  109.     if (keymatch(arg, "arithmetic", 1)) {
  110.       /* Use arithmetic coding. */
  111. #ifdef C_ARITH_CODING_SUPPORTED
  112.       cinfo->arith_code = TRUE;
  113. #else
  114.       fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
  115.           progname);
  116.       exit(EXIT_FAILURE);
  117. #endif
  118.  
  119.     } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
  120.       /* Enable debug printouts. */
  121.       /* On first -d, print version identification */
  122.       static boolean printed_version = FALSE;
  123.  
  124.       if (! printed_version) {
  125.     fprintf(stderr, "Independent JPEG Group's JPEGTRAN, version %s\n%s\n",
  126.         JVERSION, JCOPYRIGHT);
  127.     printed_version = TRUE;
  128.       }
  129.       cinfo->err->trace_level++;
  130.  
  131.     } else if (keymatch(arg, "maxmemory", 3)) {
  132.       /* Maximum memory in Kb (or Mb with 'm'). */
  133.       long lval;
  134.       char ch = 'x';
  135.  
  136.       if (++argn >= argc)    /* advance to next argument */
  137.     usage();
  138.       if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
  139.     usage();
  140.       if (ch == 'm' || ch == 'M')
  141.     lval *= 1000L;
  142.       cinfo->mem->max_memory_to_use = lval * 1000L;
  143.  
  144.     } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
  145.       /* Enable entropy parm optimization. */
  146. #ifdef ENTROPY_OPT_SUPPORTED
  147.       cinfo->optimize_coding = TRUE;
  148. #else
  149.       fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
  150.           progname);
  151.       exit(EXIT_FAILURE);
  152. #endif
  153.  
  154.     } else if (keymatch(arg, "outfile", 4)) {
  155.       /* Set output file name. */
  156.       if (++argn >= argc)    /* advance to next argument */
  157.     usage();
  158.       outfilename = argv[argn];    /* save it away for later use */
  159.  
  160.     } else if (keymatch(arg, "progressive", 1)) {
  161.       /* Select simple progressive mode. */
  162. #ifdef C_PROGRESSIVE_SUPPORTED
  163.       simple_progressive = TRUE;
  164.       /* We must postpone execution until num_components is known. */
  165. #else
  166.       fprintf(stderr, "%s: sorry, progressive output was not compiled\n",
  167.           progname);
  168.       exit(EXIT_FAILURE);
  169. #endif
  170.  
  171.     } else if (keymatch(arg, "restart", 1)) {
  172.       /* Restart interval in MCU rows (or in MCUs with 'b'). */
  173.       long lval;
  174.       char ch = 'x';
  175.  
  176.       if (++argn >= argc)    /* advance to next argument */
  177.     usage();
  178.       if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
  179.     usage();
  180.       if (lval < 0 || lval > 65535L)
  181.     usage();
  182.       if (ch == 'b' || ch == 'B') {
  183.     cinfo->restart_interval = (unsigned int) lval;
  184.     cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */
  185.       } else {
  186.     cinfo->restart_in_rows = (int) lval;
  187.     /* restart_interval will be computed during startup */
  188.       }
  189.  
  190.     } else if (keymatch(arg, "scans", 2)) {
  191.       /* Set scan script. */
  192. #ifdef C_MULTISCAN_FILES_SUPPORTED
  193.       if (++argn >= argc)    /* advance to next argument */
  194.     usage();
  195.       scansarg = argv[argn];
  196.       /* We must postpone reading the file in case -progressive appears. */
  197. #else
  198.       fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n",
  199.           progname);
  200.       exit(EXIT_FAILURE);
  201. #endif
  202.  
  203.     } else {
  204.       usage();            /* bogus switch */
  205.     }
  206.   }
  207.  
  208.   /* Post-switch-scanning cleanup */
  209.  
  210.   if (for_real) {
  211.  
  212. #ifdef C_PROGRESSIVE_SUPPORTED
  213.     if (simple_progressive)    /* process -progressive; -scans can override */
  214.       jpeg_simple_progression(cinfo);
  215. #endif
  216.  
  217. #ifdef C_MULTISCAN_FILES_SUPPORTED
  218.     if (scansarg != NULL)    /* process -scans if it was present */
  219.       if (! read_scan_script(cinfo, scansarg))
  220.     usage();
  221. #endif
  222.   }
  223.  
  224.   return argn;            /* return index of next arg (file name) */
  225. }
  226.  
  227.  
  228. /*
  229.  * The main program.
  230.  */
  231.  
  232. GLOBAL int
  233. main (int argc, char **argv)
  234. {
  235.   struct jpeg_decompress_struct srcinfo;
  236.   struct jpeg_compress_struct dstinfo;
  237.   struct jpeg_error_mgr jsrcerr, jdsterr;
  238. #ifdef PROGRESS_REPORT
  239.   struct cdjpeg_progress_mgr progress;
  240. #endif
  241.   jvirt_barray_ptr * coef_arrays;
  242.   int file_index;
  243.   FILE * input_file;
  244.   FILE * output_file;
  245.  
  246.   /* On Mac, fetch a command line. */
  247. #ifdef USE_CCOMMAND
  248.   argc = ccommand(&argv);
  249. #endif
  250.  
  251.   progname = argv[0];
  252.   if (progname == NULL || progname[0] == 0)
  253.     progname = "jpegtran";    /* in case C library doesn't provide it */
  254.  
  255.   /* Initialize the JPEG decompression object with default error handling. */
  256.   srcinfo.err = jpeg_std_error(&jsrcerr);
  257.   jpeg_create_decompress(&srcinfo);
  258.   /* Initialize the JPEG compression object with default error handling. */
  259.   dstinfo.err = jpeg_std_error(&jdsterr);
  260.   jpeg_create_compress(&dstinfo);
  261.  
  262.   /* Now safe to enable signal catcher.
  263.    * Note: we assume only the decompression object will have virtual arrays.
  264.    */
  265. #ifdef NEED_SIGNAL_CATCHER
  266.   enable_signal_catcher((j_common_ptr) &srcinfo);
  267. #endif
  268.  
  269.   /* Scan command line to find file names.
  270.    * It is convenient to use just one switch-parsing routine, but the switch
  271.    * values read here are ignored; we will rescan the switches after opening
  272.    * the input file.
  273.    */
  274.  
  275.   file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE);
  276.   jsrcerr.trace_level = jdsterr.trace_level;
  277.  
  278. #ifdef TWO_FILE_COMMANDLINE
  279.   /* Must have either -outfile switch or explicit output file name */
  280.   if (outfilename == NULL) {
  281.     if (file_index != argc-2) {
  282.       fprintf(stderr, "%s: must name one input and one output file\n",
  283.           progname);
  284.       usage();
  285.     }
  286.     outfilename = argv[file_index+1];
  287.   } else {
  288.     if (file_index != argc-1) {
  289.       fprintf(stderr, "%s: must name one input and one output file\n",
  290.           progname);
  291.       usage();
  292.     }
  293.   }
  294. #else
  295.   /* Unix style: expect zero or one file name */
  296.   if (file_index < argc-1) {
  297.     fprintf(stderr, "%s: only one input file\n", progname);
  298.     usage();
  299.   }
  300. #endif /* TWO_FILE_COMMANDLINE */
  301.  
  302.   /* Open the input file. */
  303.   if (file_index < argc) {
  304.     if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
  305.       fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
  306.       exit(EXIT_FAILURE);
  307.     }
  308.   } else {
  309.     /* default input file is stdin */
  310.     input_file = read_stdin();
  311.   }
  312.  
  313.   /* Open the output file. */
  314.   if (outfilename != NULL) {
  315.     if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
  316.       fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
  317.       exit(EXIT_FAILURE);
  318.     }
  319.   } else {
  320.     /* default output file is stdout */
  321.     output_file = write_stdout();
  322.   }
  323.  
  324. #ifdef PROGRESS_REPORT
  325.   start_progress_monitor((j_common_ptr) &dstinfo, &progress);
  326. #endif
  327.  
  328.   /* Specify data source for decompression */
  329.   jpeg_stdio_src(&srcinfo, input_file);
  330.  
  331.   /* Read file header */
  332.   (void) jpeg_read_header(&srcinfo, TRUE);
  333.  
  334.   /* Read source file as DCT coefficients */
  335.   coef_arrays = jpeg_read_coefficients(&srcinfo);
  336.  
  337.   /* Initialize destination compression parameters from source values */
  338.   jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
  339.  
  340.   /* Adjust default compression parameters by re-parsing the options */
  341.   file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE);
  342.  
  343.   /* Specify data destination for compression */
  344.   jpeg_stdio_dest(&dstinfo, output_file);
  345.  
  346.   /* Start compressor */
  347.   jpeg_write_coefficients(&dstinfo, coef_arrays);
  348.  
  349.   /* ought to copy source comments here... */
  350.  
  351.   /* Finish compression and release memory */
  352.   jpeg_finish_compress(&dstinfo);
  353.   jpeg_destroy_compress(&dstinfo);
  354.   (void) jpeg_finish_decompress(&srcinfo);
  355.   jpeg_destroy_decompress(&srcinfo);
  356.  
  357.   /* Close files, if we opened them */
  358.   if (input_file != stdin)
  359.     fclose(input_file);
  360.   if (output_file != stdout)
  361.     fclose(output_file);
  362.  
  363. #ifdef PROGRESS_REPORT
  364.   end_progress_monitor((j_common_ptr) &dstinfo);
  365. #endif
  366.  
  367.   /* All done. */
  368.   exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS);
  369.   return 0;            /* suppress no-return-value warnings */
  370. }
  371.